require 'rubygems'
require 'net/http'
require 'zip/zip'
require 'fileutils'
require 'find'

module Installr::Server::Command
  class App < Base
    def unzip(zip, unzip_dir, remove_after = false)
      Zip::ZipFile.open(zip) do |zip_file|
        zip_file.each do |f|
          f_path=File.join(unzip_dir, f.name)
          FileUtils.mkdir_p(File.dirname(f_path))
          zip_file.extract(f, f_path) unless File.exist?(f_path)
        end
      end
      FileUtils.rm(zip) if remove_after
    end

    def zip(dir, zip_dir, remove_after = false)
      Zip::ZipFile.open(zip_dir, Zip::ZipFile::CREATE) do |zipfile|
        Find.find(dir) do |path|
          Find.prune if File.basename(path)[0] == ?.
          dest = /#{dir}\/(\w.*)/.match(path)
          # Skip files if they exists
          begin
            zipfile.add(dest[1],path) if dest
          rescue Zip::ZipEntryExistsError
          end
        end
      end
      FileUtils.rm_rf(dir, :secure=>true) if remove_after
    end

    def deploy(app_name, war_file, hexdigest, remote_file_path)
      puts "[app:deploy] ***** deploy #{app_name}, #{war_file}, #{hexdigest}, #{remote_file_path}" if @options[:verbose]
      @log.info("[app:deploy] ***** deploy #{app_name}, #{war_file}, #{hexdigest}, #{remote_file_path}")

      ts = Time.now.utc.strftime("%Y_%m_%d_%H_%M_%S")
      return @storage.create_deployment(app_name, ts, war_file, hexdigest, remote_file_path)
    end

    def undeploy(app_name)
      puts "[app:undeploy] ***** undeploy #{app_name}" if @options[:verbose]
      @log.info("[app:undeploy] ***** undeploy #{app_name}")

      app = @storage.info_deployment(app_name, '0')
      if app
        deactivate(app_name)
      end
      apps = @storage.history_deployment(app_name)
      apps.each { |app| FileUtils.rm_rf(File.dirname(app[3]), :secure=>true) }
      return @storage.delete_deployment(app_name)
    end

    def activate(app_name, hexdigest)
      puts "[app:activate] ***** activate #{app_name}, #{hexdigest}" if @options[:verbose]
      @log.info("[app:activate] ***** activate #{app_name}, #{hexdigest}")

      app = @storage.info_deployment(app_name, hexdigest)

      if app
        return -1 unless File.exist?(app[3])

        FileUtils.move app[3], app[3] + '.orig'
        fname = app[3].dup
        bname = fname.chomp(File.extname(fname))

        unzip(app[3] + '.orig', bname, false)

        if File.exist?(bname + "/WEB-INF/build.xml") and File.exist?(bname + "/WEB-INF/ivy.xml") and File.exist?(bname + "/WEB-INF/ivysettings.xml")
          cmd = "ant -f " + bname + "/WEB-INF/build.xml retrieve 2>&1"

          IO.popen(cmd) do |pipe|
            pipe.sync = true
            while str = pipe.gets
              puts str
            end
          end

          FileUtils.rm bname + "/WEB-INF/build.xml"
          FileUtils.rm bname + "/WEB-INF/ivy.xml"
          FileUtils.rm bname + "/WEB-INF/ivysettings.xml"
        end

        result = @manager.deploy(app_name, bname)
        # after activation, force to stop service
        #@manager.stop(app_name)
        FileUtils.rm_rf(bname, :secure=>true)
        FileUtils.move app[3] + '.orig', app[3]
        return result
      else
        @log.error("[app:activate] cannot find app_name #{app_name}")
        return "cannot find app_name #{app_name}"
      end
    end

    def deactivate(app_name)
      puts "[app:deactivate] ***** deactivate #{app_name}" if @options[:verbose]
      @log.info("[app:deactivate] ***** deactivate #{app_name}")

      app = @storage.info_deployment(app_name, '0')
      if app
        @manager.stop(app_name)
        @manager.undeploy(app_name)
      else
        @log.error("[app:deactivate] cannot find app_name #{app_name}")
        return "cannot find app_name #{app_name}"
      end
    end

    def start(app_name)
      puts "[app:start] ***** start #{app_name}" if @options[:verbose]
      @log.info("[app:start] ***** start #{app_name}")

      app = @storage.info_deployment(app_name, '0')
      if app
        @manager.start(app_name)
      else
        @log.error("[app:start] cannot find app_name #{app_name}")
        return "cannot find app_name #{app_name}"
      end
    end

    def stop(app_name)
      puts "[app:stop] ***** stop #{app_name}" if @options[:verbose]
      @log.info("[app:stop] ***** stop #{app_name}")

      app = @storage.info_deployment(app_name, '0')
      if app
        @manager.stop(app_name)
      else
        @log.error("[app:stop] cannot find app_name #{app_name}")
        return "cannot find app_name #{app_name}"
      end
    end

    def info(app_name)
      puts "[app:info] ***** info #{app_name}" if @options[:verbose]
      @log.info("[app:info] ***** info #{app_name}")

      @storage.info_deployment(app_name, '0')
    end

    def head(app_name, app_md5hash)
      puts "[app:head] ***** head #{app_name}, #{app_md5hash}" if @options[:verbose]
      @log.info("[app:head] ***** head #{app_name}, #{app_md5hash}")

      @storage.change_deployment(app_name, app_md5hash)
    end

    def history(app_name)
      puts "[app:history] ***** history #{app_name}" if @options[:verbose]
      @log.info("[app:history] ***** history #{app_name}")

      @storage.history_deployment(app_name)
    end
  end
end
